package ffmpeg

import (
    "fmt"
    "os/exec"
    "os"
    "bufio"
    "strings"
    "net/http"
    "strconv"
    "time"
    "path/filepath"
    "github.com/gin-gonic/gin"
    "github.com/gorilla/websocket"
)

type Progress_struct struct {
    Frame  	       float64
    Fps            string
    Stream_0_0_q   string
    Bitrate	       string
    Total_size     string
    Out_time_us    int64
    Out_time_ms    int64
    Out_time       string
    Dup_frames     string
    Drop_frames    string
    Speed          string
    Progress       string
    Maxframe       float64
    Type           int64
}


var ffmpeg_run_list = make(map[string]*Progress_struct)


var upGrader = websocket.Upgrader{
    CheckOrigin: func (r *http.Request) bool {
    return true
    },
}


func Seek_ffmpeg(cont *gin.Context) {
    ws, err := upGrader.Upgrade(cont.Writer, cont.Request, nil)
    if err != nil {
        return
    }
    defer ws.Close()
    type_send, message, err := ws.ReadMessage()
    if err != nil {
        return
    }
    //fmt.Println("打开链接", string(message))
    id := string(message)
    go func(){
        for {
            _, _, err := ws.ReadMessage()
            if err != nil {
                break
            }
        }
    }()
    var sendmsg string
    for {
        body, ok := ffmpeg_run_list[id]
        if (ok) {
            switch body.Type {
                case 1:
                    sendmsg = fmt.Sprintf("%.2f",(body.Frame/body.Maxframe)*float64(100))
                case 2:
                    sendmsg = fmt.Sprintf("%.2f",(float64(body.Out_time_ms/1000000)/body.Maxframe)*float64(100))
            }
            err = ws.WriteMessage(type_send, []byte(sendmsg))
            if err != nil {
                break
            }
        }else{
            sendmsg = "没有在转换"
            ws.WriteMessage(type_send, []byte(sendmsg))
            break
        }
        time.Sleep(time.Second)
    }
}


func Addffmpeg_mp3(id string, filename string, base_path string, call func()) {
    file_path := filepath.Join(base_path, id, filename)
    out, err := exec.Command("./ffmpeg/ffprobe.exe","-v","error","-select_streams","v:0","-show_entries","stream=duration","-of","default=noprint_wrappers=1:nokey=1", file_path).Output()
    if err == nil {

        val := strings.Split(string(out), "\n")[0]
        if value, err := strconv.ParseFloat(strings.Replace(val, "\r", "", -1), 64); err == nil {
            var myprog = &Progress_struct{
                Maxframe : value,
                Type : int64(2),
            }
            new_file_path := filepath.Join(base_path, id, filename + "out.mp3")
            ecal := func() error {
                err := os.Remove(file_path)
                if err != nil {
                    return err
                }
                new_new_file_path := strings.TrimSuffix(filename, filepath.Ext(filename)) + ".mp3"
                err = os.Rename(new_file_path, filepath.Join(base_path, id, new_new_file_path))
                if err != nil {
                    return err
                }
                return nil
            }
            cmd := exec.Command("./ffmpeg/ffmpeg.exe","-i", file_path, new_file_path,"-nostats","-progress","-")
            run_ffmpeg(id, cmd, myprog, call, ecal)
        }
        
    }
    
}


func Addffmpeg_mp4(id string, filename string, base_path string, call func()) {
    file_path := filepath.Join(base_path, id, filename)
    out, err := exec.Command("./ffmpeg/ffprobe.exe","-v","error","-select_streams","v:0","-count_packets","-show_entries","stream=nb_read_packets","-of","default=nokey=1:noprint_wrappers=1", file_path).Output()
    if err == nil {
        val := strings.Split(string(out), "\n")[0]
        if value, err := strconv.ParseFloat(strings.Replace(val, "\r", "", -1), 64); err == nil {
            var myprog = &Progress_struct{
                Maxframe : value,
                Type : int64(1),
            }
            new_file_path := filepath.Join(base_path, id, filename + "out.mp4")
            ecal := func() error {
                err := os.Remove(file_path)
                if err != nil {
                    return err
                }
                new_new_file_path := strings.TrimSuffix(filename, filepath.Ext(filename)) + ".mp4"
                err = os.Rename(new_file_path, filepath.Join(base_path, id, new_new_file_path))
                if err != nil {
                    return err
                }
                return nil
            }
            cmd := exec.Command("./ffmpeg/ffmpeg.exe", "-i", file_path, "-vcodec", "h264", new_file_path, "-nostats", "-progress", "-")
            run_ffmpeg(id, cmd, myprog, call, ecal)
        }
    }
}


func Isrun(id string) bool {
    _, ok := ffmpeg_run_list[id]
    if (ok) {
        return true
    }else{
        return false
    }
}


func run_ffmpeg(id string, cmd *exec.Cmd, myprog *Progress_struct, call1 func(), call2 func() error) {
    ffmpeg_run_list[id] = myprog
    pipe, _ := cmd.StdoutPipe()
    cmd.Start()
    reader := bufio.NewReader(pipe)
    line, err := reader.ReadString('\n')
    go func () {
        for err == nil {
            size := strings.Split(strings.Replace(line, "\n", "", -1), "=")
            switch size[0] {
                case "frame":
                    myprog.Frame, _ = strconv.ParseFloat(size[1], 64)
                case "fps":
                    myprog.Fps = size[1]
                case "stream_0_0_q":
                    myprog.Stream_0_0_q = size[1]
                case "bitrate":
                    myprog.Bitrate = size[1]
                case "total_size":
                    myprog.Total_size = size[1]
                case "out_time_us":
                    myprog.Out_time_us, _ = strconv.ParseInt(size[1], 10, 64)
                case "out_time_ms":
                    myprog.Out_time_ms, _ = strconv.ParseInt(size[1], 10, 64)
                case "out_time":
                    myprog.Out_time = size[1]
                case "dup_frames":
                    myprog.Dup_frames = size[1]
                case "drop_frames":
                    myprog.Drop_frames = size[1]
                case "speed":
                    myprog.Speed = size[1]
                case "progress":
                   myprog.Progress = size[1]
                default:
            }
            line, err = reader.ReadString('\n')
        }
        delete(ffmpeg_run_list, id)
        time.Sleep(1*time.Second) //等待1秒
        if call2() == nil {
            call1()
        }
    }()
}